package com.wjsh.unboundedlifeforcustomer.app;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.net.ParseException;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;

import com.google.gson.JsonIOException;
import com.google.gson.JsonParseException;
import com.readystatesoftware.chuck.ChuckInterceptor;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import com.wjsh.common.base.App;
import com.wjsh.common.base.delegate.AppLifecycles;
import com.wjsh.common.di.module.GlobalConfigModule;
import com.wjsh.common.http.GlobalHttpHandler;
import com.wjsh.common.http.RequestInterceptor;
import com.wjsh.common.integration.ConfigModule;
import com.wjsh.common.integration.IRepositoryManager;
import com.wjsh.common.utils.UiUtils;
import com.wjsh.unboundedlifeforcustomer.BuildConfig;
import com.wjsh.unboundedlifeforcustomer.mvp.model.api.Api;
import com.wjsh.unboundedlifeforcustomer.mvp.model.api.service.CommonService;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.HttpException;
import timber.log.Timber;

/**
 * Created by chenbaolin on 2017/8/10.
 */

public class GlobalConfiguration implements ConfigModule {
    @Override
    public void applyOptions(Context context, GlobalConfigModule.Builder builder) {
        if (!BuildConfig.LOG_DEBUG) //Release 时,让框架不再打印 Http 请求和响应的信息
            builder.printHttpLogLevel(RequestInterceptor.Level.NONE);

        builder.baseurl(Api.APP_DOMAIN).globalHttpHandler(new GlobalHttpHandler() {// 这里可以提供一个全局处理Http请求和响应结果的处理类,
            // 这里可以比客户端提前一步拿到服务器返回的结果,可以做一些操作,比如token超时,重新获取
            @Override
            public Response onHttpResultResponse(String httpResult, Interceptor.Chain chain, Response response) {
                 /* 这里可以先客户端一步拿到每一次http请求的结果,可以解析成json,做一些操作,如检测到token过期后
                           重新请求token,并重新执行请求 */
                try {
                    if (!TextUtils.isEmpty(httpResult) && RequestInterceptor.isJson(response.body().contentType())) {
                        JSONArray array = new JSONArray(httpResult);
                        JSONObject object = (JSONObject) array.get(0);
                        String login = object.getString("login");
                        String avatar_url = object.getString("avatar_url");
                        Timber.w("Result ------> " + login + "    ||   Avatar_url------> " + avatar_url);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                    return response;
                }
          /* 这里如果发现token过期,可以先请求最新的token,然后在拿新的token放入request里去重新请求
                        注意在这个回调之前已经调用过proceed,所以这里必须自己去建立网络请求,如使用okhttp使用新的request去请求
                        create a new request and modify it accordingly using the new token
                        Request newRequest = chain.request().newBuilder().header("token", newToken).build();
                        //retry the request
                        response.body().close();
                        如果使用okhttp将新的请求,请求成功后,将返回的response  return出去即可
                        如果不需要返回新的结果,则直接把response参数返回出去 */

                return response;
            }

            // 这里可以在请求服务器之前可以拿到request,做一些操作比如给request统一添加token或者header以及参数加密等操作
            @Override
            public Request onHttpRequestBefore(Interceptor.Chain chain, Request request) {
                 /* 如果需要再请求服务器之前做一些操作,则重新返回一个做过操作的的request如增加header,不做操作则直接返回request参数
                           return chain.request().newBuilder().header("token", tokenId)
                                  .build(); */
                return request;
            }
        }).responseErrorListener((context1, t) -> {
             /* 用来提供处理所有错误的监听rxJava必须要使用ErrorHandleSubscriber
         (默认实现Subscriber的onError方法),此监听才生效 */
            Timber.tag("Catch-Error").w(t.getMessage());
            //这里不光是只能打印错误,还可以根据不同的错误作出不同的逻辑处理
            String msg = "未知错误";
            if (t instanceof UnknownHostException) {
                msg = "网络不可用";
            } else if (t instanceof SocketTimeoutException) {
                msg = "请求网络超时";
            } else if (t instanceof HttpException) {
                HttpException httpException = (HttpException) t;
                msg = convertStatusCode(httpException);
            } else if (t instanceof JsonParseException ||
                    t instanceof ParseException ||
                    t instanceof JsonIOException ||
                    t instanceof JSONException) {
                msg = "数据解析错误";
            }
            UiUtils.snackbarText(msg);
        }).gsonConfiguration((context1, gsonBuilder) -> {
            //这里可以自己自定义配置Gson的参数
            gsonBuilder.serializeNulls()//支持序列化null的参数
                    //支持将序列化key为object的map,默认只能序列化key为string的map
                    .enableComplexMapKeySerialization();

        }).retrofitConfiguration((context1, retrofitBuilder) -> {
            //这里可以自己自定义配置Retrofit的参数,甚至你可以替换系统配置好的okHttp对象
        }).okhttpConfiguration((context1, okHttpBuilder) -> {
            //这里可以自己自定义配置Okhttp的参数
            okHttpBuilder.writeTimeout(10, TimeUnit.SECONDS)
                    .addInterceptor(new ChuckInterceptor(context1));//添加拦截器

        }).rxCacheConfiguration((context1, rxCacheBuilder) -> {
            //这里可以自己自定义配置RxCache的参数
            rxCacheBuilder.useExpiredDataIfLoaderNotAvailable(true);
        });

    }

    @Override
    public void registerComponents(Context context, IRepositoryManager repositoryManager) {
        repositoryManager.injectRetrofitService(CommonService.class);
        repositoryManager.injectCacheService(CommonService.class);

    }

    @Override
    public void injectAppLifecycle(Context context, List<AppLifecycles> lifecycles) {
        // AppDelegate.Lifecycle 的所有方法都会在基类Application对应的生命周期中被调用,所以在对应的方法中可以扩展一些自己需要的逻辑
        lifecycles.add(new AppLifecycles() {
            @Override
            public void attachBaseContext(Context base) {

            }

            @Override
            public void onCreate(Application application) {
                if (BuildConfig.LOG_DEBUG) {//Timber日志打印
                    Timber.plant(new Timber.DebugTree());
                }
                //leakCanary内存泄露检查
                ((App) application).getAppComponent().extras().put(RefWatcher.class.getName(),
                        BuildConfig.USE_CANARY ? LeakCanary.install(application) : RefWatcher.DISABLED);
            }

            @Override
            public void onTerminate(Application application) {

            }
        });

    }

    @Override
    public void injectActivityLifecycle(Context context, List<Application.ActivityLifecycleCallbacks> lifecycles) {
        lifecycles.add(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            }

            @Override
            public void onActivityStarted(Activity activity) {
                Timber.w(activity + " - onActivityStarted");
            }

            @Override
            public void onActivityResumed(Activity activity) {
                Timber.w(activity + " - onActivityResumed");
            }

            @Override
            public void onActivityPaused(Activity activity) {
                Timber.w(activity + " - onActivityPaused");
            }

            @Override
            public void onActivityStopped(Activity activity) {
                Timber.w(activity + " - onActivityStopped");
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
                Timber.w(activity + " - onActivitySaveInstanceState");
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
                Timber.w(activity + " - onActivityDestroyed");
            }
        });

    }

    @Override
    public void injectFragmentLifecycle(Context context, List<FragmentManager.FragmentLifecycleCallbacks> lifecycles) {
        lifecycles.add(new FragmentManager.FragmentLifecycleCallbacks() {

            @Override
            public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
                // 在配置变化的时候将这个 Fragment 保存下来,在 Activity 由于配置变化重建是重复利用已经创建的Fragment。
                // https://developer.android.com/reference/android/app/Fragment.html?hl=zh-cn#setRetainInstance(boolean)
                // 在 Activity 中绑定少量的 Fragment 建议这样做,如果需要绑定较多的 Fragment 不建议设置此参数,如 ViewPager 需要展示较多 Fragment
                f.setRetainInstance(true);
            }

            @Override
            public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
                //这里应该是检测 Fragment 而不是 FragmentLifecycleCallbacks 的泄露。
                ((RefWatcher) ((App) (f.getActivity())
                        .getApplication())
                        .getAppComponent()
                        .extras()
                        .get(RefWatcher.class.getName()))
                        .watch(f);

            }
        });
    }

    private String convertStatusCode(HttpException httpException) {
        String msg;
        if (httpException.code() == 500) {
            msg = "服务器发生错误";
        } else if (httpException.code() == 404) {
            msg = "请求地址不存在";
        } else if (httpException.code() == 403) {
            msg = "请求被服务器拒绝";
        } else if (httpException.code() == 307) {
            msg = "请求被重定向到其他页面";
        } else {
            msg = httpException.message();
        }
        return msg;
    }


}
